package com.coda;


import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;


/**
 *  @date 2024-012-20 20:15:22
 */
public class GamePanel extends JPanel implements KeyListener, ActionListener {
    //蛇的长度
    private int length;
    //蛇的坐标
    private int[] snakeX = new int[600];
    private int[] snakeY = new int[500];
    //蛇的默认方向
    private String fx;
    //判断游戏是否开始
    private boolean isStart = false;
    //定时器,300毫秒执行一次
    private Timer timer;
    //积分
    private int score;
    //模式
    private String type = "";
    //食物坐标
    private int foodX;
    private int foodY;
    //游戏失败判断
    private boolean isFail = false;

    Random random = new Random();

    public GamePanel(){
        init();
        this.setFocusable(true);  //设置当前组件可以获取焦点
        this.addKeyListener(this); //为当前组件添加了键盘监听器
        setTimerInterval(300); //执行定时器
    }

    //初始化参数
    public void init(){
        length = 3;
        //头部坐标
        snakeX[0] = 93; snakeY[0] = 100;
        //第一个生身体坐标
        snakeX[1] = 68; snakeY[1] = 100;
        //第二个身体坐标
        snakeX[2] = 43; snakeY[2] = 100;
        //初始化方向为右
        fx = "R";
        //随机生成食物
        foodX = 18 + 25 * random.nextInt(34);
        foodY = 75 + 25 * random.nextInt(24);

        //初始化积分
        score = 0;
    }

    @Override
    protected void paintComponent(Graphics g) {
        //清屏
        super.paintComponent(g);
        //设置背景图片
        this.setBackground(Color.white);
        //绘制顶部标题
        Data.header.paintIcon(this,g,18,11);
        //绘制游戏区域
        g.fillRect(18,75,850,600);

        //画一条静态小蛇,判断蛇头的方向
        if ("R".equals(fx)){
            Data.right.paintIcon(this,g,snakeX[0],snakeY[0]);
        } else if ("L".equals(fx)) {
            Data.left.paintIcon(this,g,snakeX[0],snakeY[0]);
        } else if ("D".equals(fx)) {
            Data.down.paintIcon(this,g,snakeX[0],snakeY[0]);
        } else if ("U".equals(fx)) {
            Data.up.paintIcon(this,g,snakeX[0],snakeY[0]);
        }

        //绘制蛇的身体
        for (int i = 1; i < length; i++) {
            Data.body.paintIcon(this,g,snakeX[i],snakeY[i]);
        }

        //绘制食物
        Data.food.paintIcon(this,g,foodX,foodY);

        //绘制积分区域
        g.setColor(Color.white);
        g.setFont(new Font("微软雅黑",Font.BOLD,18));
        g.drawString("长度："+length,750,32);
        g.drawString("分数："+length,750,52);

        //设置游戏模式
        if ("".equals(type)){
            g.setColor(Color.white);
            g.setFont(new Font("微软雅黑",Font.BOLD,26));
            g.drawString("W: 无尽模式",350,300);
            g.drawString("T: 挑战模式",350,350);
            g.drawString("K：困难模式",350,400);
            g.drawString("ESC: 返回主界面",350,450);
        }

        //游戏提示：是否开始
        if (isStart == false && !("".equals(type))){
            g.setColor(Color.white);
            g.setFont(new Font("微软雅黑",Font.BOLD,40));
            g.drawString("按下空格键开始",300,300);
        }

        //失败提醒
        if (isFail && !("".equals(type))){
            g.setColor(Color.white);
            g.setFont(new Font("微软雅黑",Font.BOLD,40));
            g.drawString("游戏失败，按下空格键重新开始",200,300);
        }
    }




    @Override
    public void keyPressed(KeyEvent e) {
        //获取键盘录入的字符
        int keyCode = e.getKeyCode();

        //W：无尽模式
        if (keyCode == KeyEvent.VK_W){
            type = "W";
            repaint();
        }
        //T：挑战模式
        if (keyCode == KeyEvent.VK_T){
            type = "T";
            repaint();
        }
        //K: 困难模式，（这里将type设置为T可以少写困难模式代码）
        if (keyCode == KeyEvent.VK_K){
            type = "T";
            setTimerInterval(100);
            repaint();
        }
        //ESC：返回主页
        if (keyCode == KeyEvent.VK_ESCAPE){
            type = "";
            isFail = false;
            isStart = false;
            setTimerInterval(300);
            init();
            repaint();
        }
        //按下空格键刷新页面
        if (keyCode == KeyEvent.VK_SPACE){
            if (isFail) { // 如果游戏失败,从头再来
                isFail = false;
                init();
            }else {  //如果没失败就暂停游戏
                isStart = !isStart;
            }
            repaint();
        }

        //键盘控制方向，且不能掉头
        if(keyCode == KeyEvent.VK_UP && !("D".equals(fx))){
            fx = "U";
        } else if (keyCode == KeyEvent.VK_DOWN && !("U".equals(fx))) {
            fx = "D";
        } else if (keyCode == KeyEvent.VK_LEFT && !("R".equals(fx))) {
            fx = "L";
        } else if (keyCode == KeyEvent.VK_RIGHT && !("L".equals(fx))) {
            fx = "R";
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println(snakeX[0]+" "+snakeY[0]);
        //如果游戏是开始状态，并且没有失败，并且是无尽模式
        if (isFail == false && isStart && "W".equals(type)){
            move();

            //判断方向
            if ("R".equals(fx)){ //右，头部x坐标+25
                snakeX[0] = snakeX[0] + 25;
                if (snakeX[0] > 843){ //如果头部超出了右边界范围，则从左边界出来
                    snakeX[0] = 18;
                }
            }
            if ("L".equals(fx)){ //左，头部x左边-25
                snakeX[0] = snakeX[0] - 25;
                if (snakeX[0] < 18){ //如果头部超出了左边界，则从右边出来
                    snakeX[0] = 843;
                }
            }
            if ("U".equals(fx)){  //上，头部y坐标-25
                snakeY[0] = snakeY[0] - 25;
                if (snakeY[0] < 75){ //如果头部超出了上边界，则从下边界出来
                    snakeY[0] = 650;
                }
            }
            if ("D".equals(fx)){ //下，头部y坐标+25
                snakeY[0] = snakeY[0] + 25;
                if (snakeY[0] > 650){ //如果超出下边界，则从上边界出来
                    snakeY[0] = 75;
                }
            }

            //如果头和食物碰到了则吃到食物，长度+1
            eat();
            //结束判断
            over();
            //刷新界面
            repaint();

        }

        //游戏已开始，并别没有失败，并且是挑战模式
        if (isStart && isFail == false && "T".equals(type)){
            //移动
            move();

            if ("R".equals(fx)){ //右，头部x坐标+25
                snakeX[0] = snakeX[0] + 25;
                if (snakeX[0] > 843){ //如果头部超出了右边界范围，则从左边界出来
                    isFail = true;
                }
            }
            if ("L".equals(fx)){ //左，头部x坐标-25
                snakeX[0] = snakeX[0] - 25;
                if (snakeX[0] < 18){ //如果头部超出了左边界范围，则从右边界出来
                    isFail = true;
                }
            }
            if ("U".equals(fx)){ //上，头部坐标-25
                snakeY[0] = snakeY[0] - 25;
                if (snakeY[0] < 75){ //如果头部超出了上边界范围，则从下边界出来
                    isFail = true;
                }
            }
            if ("D".equals(fx)){ //下，头部坐标+25
                snakeY[0] = snakeY[0] + 25;
                if (snakeY[0] > 650){ //如果头部超出了下边界范围，则从上边界出来
                    isFail = true;
                }
            }

            //吃食物
            eat();
            //结束判断
            over();
            //刷新页面
            repaint();
        }

        //刷新时间（让时间动起来）
        timer.start();

    }


    //移动
    private void move(){
        for (int i = length-1; i > 0; i--) {  //身体移动，除了头部
            //设置身体坐标，将snack数组的最后一个元素向前移动，依次操作所有的元素
            snakeX[i] = snakeX[i-1];
            snakeY[i] = snakeY[i-1];
        }
    }

    //如果头和食物重合则吃到该食物，在最后添加一个身体
    private void eat(){
        if (snakeX[0] == foodX && snakeY[0] == foodY){
            //增加长度和积分
            length++;
            score+=10;
            //添加身体
            snakeX[length-1] = snakeX[length-2] * 2 - snakeX[length-3];
            snakeY[length-1] = snakeY[length-2] * 2 - snakeY[length-3];
            //重新生成食物
            foodX = 18 + 25 * random.nextInt(34);
            foodY = 75 + 25 * random.nextInt(24);

        }
    }

    //结束游戏
    private void over(){
        //如果头部触碰到了身体的任何一个地方，则游戏失败
        for (int i = 1; i < length; i++) {
            if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]){
                isFail = true;
            }
        }
    }

    private void setTimerInterval(int time){
        //关闭当前定时器
        if (timer != null){
            timer.stop();
        }

        //重新创建定时器，指定刷新时间为50秒
        timer  = new Timer(time, this);
        //开启新的定时器
        timer.start();

    }

    @Override
    public void keyReleased(KeyEvent e) {

    }
    @Override
    public void keyTyped(KeyEvent e) {

    }
}
